<?php
$TAG_WEIGHTS = array();

class Tags extends BlockInstance {
	public $CI;
	
	function Tags()
	{
		$this->CI =& get_instance();
	}
	
	public function handle_proxy($bricabox_id, $params, $parent_name, $tpl_path, $instance, $parent)
	{
		// lots of overhead to get us back into a renderable state...
		global $BBX;
		
		ob_start();
		
		$this->CI->load->model('Content_model');
		
		$block_data['data']			 = $instance;
		$block_data['parent']		 = $parent;
		$block_data['template_path'] = $tpl_path;
		$block_data['klass'] 		 = BlockInstance::load_block_file($tpl_path, $parent_name);
		$block_data['title'] 		 = BlockInstance::title_for_block($block_data);
		
		if (isset($params['content_id']))
			$content = $this->CI->Content_model->load_content($params['content_id'], $BBX['bricabox']->id);
		
		// actually handle the user action
		switch ($params['_action'])
		{
			case 'save_tags':
			{
				// steps to take:
				// 1. split tags by commas and strip out colons
				// 2. see if the tag exists; if so, get its id, otherwise create it and return the insert_id
				// 3. add a contents_tags record if one doesn't already exist
				$raw_tags = $params['value'];
				if (!strlen($raw_tags))
					break;
					
				foreach (explode(',', $raw_tags) as $tag)
				{
					$tag = preg_replace('/[^-_a-z0-9 ]/i', '', trim($tag)); // only allow alphanumerics, -, _, and whitespace
					$exists_query = $this->CI->db->query('select id from tags where name = ? limit 1', array($tag));
					if ($exists_query->num_rows() == 1)
						$tag_id = $exists_query->first_row()->id;
					else
					{
						// create new
						$new_query = $this->CI->db->query('insert into tags (created_at,updated_at,name)
							values(NOW(),NOW(),?)',
							array($tag));
						$tag_id = $this->CI->db->insert_id();
					}
					
					// join; does it exist?
					$exists_query = $this->CI->db->query('select * from contents_tags
						where tag_id = ? and content_id = ?
						limit 1',
						array($tag_id, $content->id));
					if ($exists_query->num_rows() == 0)
						$this->CI->db->query('insert into contents_tags (tag_id,content_id,user_id)
							values(?,?,?)',
							array(
								$tag_id,
								$content->id,
								$this->CI->userland->current_user()->id
							));
							
					// add to activity stream
					$this->CI->load->model('Activity_model');
					$this->CI->Activity_model->log_tag(array(
						'user_id' => $this->CI->userland->current_user()->id,
						'subject' => username($this->CI->userland->current_user()),
						'object'  => $content->field1_value,
						'extra'	  => $tag,
						'content_id'  => $content->id,
						'bricabox_id' => $content->bricabox_id
					));
				}
			}
			break;
			
			case 'remove_tag':
			{
				$_params = array(
					$params['tag_id'],
					$params['content_id']
				);
				$this->CI->db->query('delete from contents_tags where tag_id = ? and content_id = ?', $_params);
			}
			break;
		}
		
		$cachefile = $this->_cachefile_name($BBX['bricabox'], $instance);
		if (file_exists($cachefile))
			unlink($cachefile);
			
		// load up the block again and return the generated html
		$this->either_content($block_data, $content);
		
		$_out = ob_get_contents();
		ob_end_clean();
		
		return $_out;
	}
	
	private function _cachefile_name($bricabox, $instance)
	{
		return APPPATH."../cache/tags_index_{$bricabox->id}.html";
	}
	
	function __call($m, $a)
	{
		global $BBX;
		if (preg_match('/[a-z]+_([a-z]+)/', $m, $matches))
		{
			if ($matches[1] == 'content')
			{
				$content = $a[1];
				$data 	 = array(
					'block_instance' => $a[0],
					'tags'			 => $this->_load_tags_for($content->id),
					'bricabox'		 => $BBX['bricabox'],	// pass anyway so handle_proxy() can recreate the view via ajax
					'content'		 => $content			// pass anyway so handle_proxy() can recreate the view via ajax
				);
				$this->CI->load->view('blocks/tags/content', $data);
			}
			elseif ($matches[1] == 'homepage')
			{
				// check for cached file
				$cachefile = $this->_cachefile_name($BBX['bricabox'], $a[0]['data']);
				if (false && file_exists($cachefile))
					require $cachefile;
				else
				{
					ob_start();
					$data = array(
						'bricabox'		 => $BBX['bricabox'],	// pass anyway so handle_proxy() can recreate the view via ajax
						'block_instance' => $a[0],
						'tags'			 => $this->_load_all_tags_for($a[1]) // $a[1] is a CI result of all content available in the current view
					);
					$_html = $this->CI->load->view('blocks/tags/homepage', $data, true);
					echo $_html;
					ob_end_clean();
					
					$fp = fopen($cachefile, 'w');
					fwrite($fp, $_html);
					fclose($fp);
					
					echo $_html;
				}
			}
		}
	}
	
	public function get_weight_for($bricabox, $tag)
	{
		global $TAG_WEIGHTS;
		
		$idx = 1;
		
		// try to load tag weights if a cached version doesn't exist
		if (!count($TAG_WEIGHTS))
		{
			// get all tags used in this bricabox
			$tags_query = $this->CI->db->query('select * from contents_tags
			inner join tags on tags.id=contents_tags.tag_id
			where contents_tags.content_id in
				(select contents.id from contents where contents.bricabox_id = ?)
			order by tags.name asc', array($bricabox->id));
			
			if ($tags_query->num_rows())
				foreach ($tags_query->result() as $row)
					$TAG_WEIGHTS[$row->name] = $this->_count_tagged_with($bricabox, $row->tag_id);
		}
		
		// still nothing? return the default weight index (1)
		if (!count($TAG_WEIGHTS))
			return $idx;
		
		// get the number of entries tagged with this tag in this bricabox
		$count_query = $this->CI->db->query('select count(*) as count_all from contents_tags
			inner join contents on contents.id = contents_tags.content_id
			where contents_tags.tag_id = ? and contents.bricabox_id = ?', array($tag->id, $bricabox->id));
		$count_all = $count_query->first_row()->count_all;
		
		if ($count_all)
		{
			// get the least and most used tag for this bricabox, e.g. which tags have been applied to the most entries and fewest entries
			asort($TAG_WEIGHTS);
			reset($TAG_WEIGHTS);
			$min_count = current($TAG_WEIGHTS);
			$max_count = end($TAG_WEIGHTS);

			// calculate our divisor; we have 6 possible weights (1..6)
			$divisor = (($max_count - $min_count) / 6) + 1;

			// calculate the weight index
			$idx = ceil(($count_all - $min_count) / $divisor) + 1;
		}
		
		return $idx;
	}
	
	public function user_can_edit($user, $tag)
	{
		if ($user->id == $tag->user_id)
			return true;
	}
	
	private function _load_tags_for($content_id)
	{
		// load all tags for this entry and make user_id available for each
		$query = $this->CI->db->query('select * from contents_tags
		inner join tags on tags.id=contents_tags.tag_id
		where contents_tags.content_id = ?
		order by tags.name asc', array($content_id));
		if ($query->num_rows())
			return $query;
		else
			return false;
	}
	
	private function _load_all_tags_for($content)
	{
		if ($content === false)
			return false;
		
		// load all tags for this bricabox via an IN (content ids)
		$content_ids = array();
		foreach ($content->result() as $c)
			$content_ids[] = $c->id;
		$content_ids = join(',', $content_ids);
		
		$query = $this->CI->db->query('select * from contents_tags
		inner join tags on tags.id=contents_tags.tag_id
		where contents_tags.content_id in ('.$content_ids.')
		group by contents_tags.tag_id
		order by tags.name asc');
		if ($query->num_rows())
			return $query;
		else
			return false;
	}
	
	private function _count_tagged_with($bricabox, $tag_id)
	{
		$query = $this->CI->db->query('select count(*) as count_all from contents_tags
			inner join contents on contents.id = contents_tags.content_id
			where contents_tags.tag_id = ?
				and (select contents.bricabox_id from contents
						where contents.id = contents_tags.content_id limit 1) = ?', array($tag_id, $bricabox->id));
		if ($query->num_rows() == 1)
			return $query->first_row()->count_all;
		else // just in case
			return 0;
	}
}
?>